///////////////////////////////////////////////////////////////////////////////////////////////////
// SQLite3E.cpp
// 2008?7?4?
// the base class read sqlite3 database .
// Copyright ? 2007, 2008, 8DWorld, Inc. All rights reserved.
//
#include "stdafx.h"

 #include "SQLite3E.h"
#include <cstdlib>
#include <windows.h>

static const bool DONT_DELETE_MSG=false;

int sqlite3_encode_binary(const unsigned char *in, int n, unsigned char *out);
int sqlite3_decode_binary(const unsigned char *in, unsigned char *out);


__inline void Gb2312_2_Unicode(unsigned short* dst, const char * src)
{
	::MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, src, 2, (LPWSTR)dst, 1);
}

__inline void Unicode_2_UTF8(char* dst, unsigned short* src)
{
	char* pchar = (char *)src;
	
	dst[0] = (0xE0 | ((pchar[1] & 0xF0) >> 4));
	dst[1] = (0x80 | ((pchar[1] & 0x0F) << 2)) + ((pchar[0] & 0xC0) >> 6);
	dst[2] = (0x80 | ( pchar[0] & 0x3F));
}



__inline void Unicode_2_GB2312(char* dst, unsigned short uData)
{
	WideCharToMultiByte(CP_ACP, NULL, (LPCWSTR)&uData, 1, dst, sizeof(unsigned short), NULL, NULL);
}

int GB2312_2_UTF8(char * buf, int buf_len, const char * src, int src_len)
{
	if (0 == src_len)
		src_len = (int)strlen(src);

	int j = 0;
	for (int i = 0; i < src_len;)
	{
		if (j >= buf_len - 1)
			break;

		if (src[i] >= 0)
		{
			buf[j++] = src[i++];
		}
		else
		{
			unsigned short w_c = 0;
			Gb2312_2_Unicode(&w_c, src + i);

			char tmp[4] = "";
			Unicode_2_UTF8(tmp, &w_c);
			
			buf[j+0] = tmp[0];
			buf[j+1] = tmp[1];
			buf[j+2] = tmp[2];
			
			i += 2;
			j += 3;
		}
	}

	buf[j] = '\0';

	return j;
}




CppSQLite3Exception::CppSQLite3Exception(const int nErrCode,
									char* szErrMess,
									bool bDeleteMsg/*=true*/) :
									m_nErrCode(nErrCode)
{
	m_pszErrMess = sqlite3_mprintf("%s[%d]: %s",
								errorCodeAsString(nErrCode),
								nErrCode,
								szErrMess ? szErrMess : "");

	if (bDeleteMsg && szErrMess)
	{
		sqlite3_free(szErrMess);
	}
}

									
CppSQLite3Exception::CppSQLite3Exception(const CppSQLite3Exception&  e) :
									m_nErrCode(e.m_nErrCode)
{
	m_pszErrMess = 0;
	if (e.m_pszErrMess)
	{
		m_pszErrMess = sqlite3_mprintf("%s", e.m_pszErrMess);
	}
}


const char* CppSQLite3Exception::errorCodeAsString(int nErrCode)
{
	switch (nErrCode)
	{
		case SQLITE_OK          : return "SQLITE_OK";
		case SQLITE_ERROR       : return "SQLITE_ERROR";
		case SQLITE_INTERNAL    : return "SQLITE_INTERNAL";
		case SQLITE_PERM        : return "SQLITE_PERM";
		case SQLITE_ABORT       : return "SQLITE_ABORT";
		case SQLITE_BUSY        : return "SQLITE_BUSY";
		case SQLITE_LOCKED      : return "SQLITE_LOCKED";
		case SQLITE_NOMEM       : return "SQLITE_NOMEM";
		case SQLITE_READONLY    : return "SQLITE_READONLY";
		case SQLITE_INTERRUPT   : return "SQLITE_INTERRUPT";
		case SQLITE_IOERR       : return "SQLITE_IOERR";
		case SQLITE_CORRUPT     : return "SQLITE_CORRUPT";
		case SQLITE_NOTFOUND    : return "SQLITE_NOTFOUND";
		case SQLITE_FULL        : return "SQLITE_FULL";
		case SQLITE_CANTOPEN    : return "SQLITE_CANTOPEN";
		case SQLITE_PROTOCOL    : return "SQLITE_PROTOCOL";
		case SQLITE_EMPTY       : return "SQLITE_EMPTY";
		case SQLITE_SCHEMA      : return "SQLITE_SCHEMA";
		case SQLITE_TOOBIG      : return "SQLITE_TOOBIG";
		case SQLITE_CONSTRAINT  : return "SQLITE_CONSTRAINT";
		case SQLITE_MISMATCH    : return "SQLITE_MISMATCH";
		case SQLITE_MISUSE      : return "SQLITE_MISUSE";
		case SQLITE_NOLFS       : return "SQLITE_NOLFS";
		case SQLITE_AUTH        : return "SQLITE_AUTH";
		case SQLITE_FORMAT      : return "SQLITE_FORMAT";
		case SQLITE_RANGE       : return "SQLITE_RANGE";
		case SQLITE_ROW         : return "SQLITE_ROW";
		case SQLITE_DONE        : return "SQLITE_DONE";
		case CPPSQLITE_ERROR    : return "CPPSQLITE_ERROR";
		default: return "UNKNOWN_ERROR";
	}
}


CppSQLite3Exception::~CppSQLite3Exception()
{
	if (m_pszErrMess)
	{
		sqlite3_free(m_pszErrMess);
		m_pszErrMess = 0;
	}
}


////////////////////////////////////////////////////////////////////////////////

CppSQLite3Buffer::CppSQLite3Buffer()
{
	m_pBuf = 0;
}


CppSQLite3Buffer::~CppSQLite3Buffer()
{
	clear();
}


void CppSQLite3Buffer::clear()
{
	if (m_pBuf)
	{
		sqlite3_free(m_pBuf);
		m_pBuf = 0;
	}

}


const char* CppSQLite3Buffer::format(const char* szFormat, ...)
{
	clear();
	va_list va;
	va_start(va, szFormat);
	m_pBuf = sqlite3_vmprintf(szFormat, va);
	va_end(va);
	return m_pBuf;
}


////////////////////////////////////////////////////////////////////////////////

CppSQLite3Binary::CppSQLite3Binary() :
						m_pBuf(0),
						m_nBinaryLen(0),
						m_nBufferLen(0),
						m_nEncodedLen(0),
						m_bEncoded(false)
{
}


CppSQLite3Binary::~CppSQLite3Binary()
{
	clear();
}

//the sqlite 3 version can and binary data now
void CppSQLite3Binary::setBinary(const unsigned char* pBuf, int nLen)
{
	m_pBuf = allocBuffer(nLen);
	memcpy(m_pBuf, pBuf, nLen);
}


void CppSQLite3Binary::setEncoded(const unsigned char* pBuf)
{
	clear();

	m_nEncodedLen =(int)strlen((const char*)pBuf);
	m_nBufferLen = m_nEncodedLen + 1; // Allow for NULL terminator

	m_pBuf = (unsigned char*)malloc(m_nBufferLen);

	if (!m_pBuf)
	{
		throw CppSQLite3Exception(CPPSQLITE_ERROR,
								"Cannot allocate memory",
								DONT_DELETE_MSG);
	}

	memcpy(m_pBuf, pBuf, m_nBufferLen);
	m_bEncoded = true;
}


const unsigned char* CppSQLite3Binary::getEncoded()
{
	if (!m_bEncoded)
	{
		unsigned char* ptmp = (unsigned char*)malloc(m_nBinaryLen);
		memcpy(ptmp, m_pBuf, m_nBinaryLen);
		m_nEncodedLen = sqlite3_encode_binary(ptmp, m_nBinaryLen, m_pBuf);
		free(ptmp);
		m_bEncoded = true;
	}

	return m_pBuf;
}


const unsigned char* CppSQLite3Binary::getBinary()
{
	if (m_bEncoded)
	{
		// in/out buffers can be the same
		m_nBinaryLen = sqlite3_decode_binary(m_pBuf, m_pBuf);

		if (m_nBinaryLen == -1)
		{
			throw CppSQLite3Exception(CPPSQLITE_ERROR,
									"Cannot decode binary",
									DONT_DELETE_MSG);
		}

		m_bEncoded = false;
	}

	return m_pBuf;
}


int CppSQLite3Binary::getBinaryLength()
{
	getBinary();
	return m_nBinaryLen;
}


unsigned char* CppSQLite3Binary::allocBuffer(int nLen)
{
	clear();

	// Allow extra space for encoded binary as per comments in
	// SQLite encode.c See bottom of this file for implementation
	// of SQLite functions use 3 instead of 2 just to be sure ;-)
	m_nBinaryLen = nLen;
	m_nBufferLen = 3 + (257*nLen)/254;

	m_pBuf = (unsigned char*)malloc(m_nBufferLen);

	if (!m_pBuf)
	{
		throw CppSQLite3Exception(CPPSQLITE_ERROR,
								"Cannot allocate memory",
								DONT_DELETE_MSG);
	}

	m_bEncoded = false;

	return m_pBuf;
}


void CppSQLite3Binary::clear()
{
	if (m_pBuf)
	{
		m_nBinaryLen = 0;
		m_nBufferLen = 0;
		free(m_pBuf);
		m_pBuf = 0;
	}
}


////////////////////////////////////////////////////////////////////////////////

CppSQLite3Query::CppSQLite3Query()
{
	m_pVM = 0;
	m_bEof = true;
	m_nCols = 0;
	m_bOwnVM = false;
}


CppSQLite3Query::CppSQLite3Query(const CppSQLite3Query& rQuery)
{
	m_pVM = rQuery.m_pVM;
	// Only one object can own the VM
	const_cast<CppSQLite3Query&>(rQuery).m_pVM = 0;
	m_bEof = rQuery.m_bEof;
	m_nCols = rQuery.m_nCols;
	m_bOwnVM = rQuery.m_bOwnVM;
}


CppSQLite3Query::CppSQLite3Query(sqlite3* pDB,
							sqlite3_stmt* pVM,
							bool bEof,
							bool bOwnVM/*=true*/)
{
	m_pDB = pDB;
	m_pVM = pVM;
	m_bEof = bEof;
	m_nCols = sqlite3_column_count(m_pVM);
	m_bOwnVM = bOwnVM;
}


CppSQLite3Query::~CppSQLite3Query()
{
	try
	{
		finalize();
	}
	catch (...)
	{
	}
}


CppSQLite3Query& CppSQLite3Query::operator=(const CppSQLite3Query& rQuery)
{
	try
	{
		finalize();
	}
	catch (...)
	{
	}
	m_pVM = rQuery.m_pVM;
	// Only one object can own the VM
	const_cast<CppSQLite3Query&>(rQuery).m_pVM = 0;
	m_bEof = rQuery.m_bEof;
	m_nCols = rQuery.m_nCols;
	m_bOwnVM = rQuery.m_bOwnVM;
	return *this;
}


int CppSQLite3Query::numFields()
{
	checkVM();
	return m_nCols;
}


const char* CppSQLite3Query::fieldValue(int nField)
{
	checkVM();

	if (nField < 0 || nField > m_nCols-1)
	{
		throw CppSQLite3Exception(CPPSQLITE_ERROR,
								"Invalid field index requested",
								DONT_DELETE_MSG);
	}

	return (const char*)sqlite3_column_text(m_pVM, nField);
}

bool CppSQLite3Query::fieldExists(const char* szField, int& col)
{
	checkVM();

	if (szField)
	{
		for (int nField = 0; nField < m_nCols; nField++)
		{
			const char* szTemp = sqlite3_column_name(m_pVM, nField);

			if (strcmp(szField, szTemp) == 0)
			{
				col = nField;
				return true;
			}
		}
	}

	return false;
}

const char* CppSQLite3Query::fieldValue(const char* szField)
{
	int nField = fieldIndex(szField);
	return (const char*)sqlite3_column_text(m_pVM, nField);
}


int CppSQLite3Query::getIntField(int nField, int nNullValue/*=0*/)
{
	if (fieldDataType(nField) == SQLITE_NULL)
	{
		return nNullValue;
	}
	else
	{
		return sqlite3_column_int(m_pVM, nField);
	}
}


int CppSQLite3Query::getIntField(const char* szField, int nNullValue/*=0*/)
{
	int nField = fieldIndex(szField);
	return getIntField(nField, nNullValue);
}


double CppSQLite3Query::getFloatField(int nField, double fNullValue/*=0.0*/)
{
	if (fieldDataType(nField) == SQLITE_NULL)
	{
		return fNullValue;
	}
	else
	{
		return sqlite3_column_double(m_pVM, nField);
	}
}


double CppSQLite3Query::getFloatField(const char* szField, double fNullValue/*=0.0*/)
{
	int nField = fieldIndex(szField);
	return getFloatField(nField, fNullValue);
}


const char* CppSQLite3Query::getStringField(int nField, const char* szNullValue/*=""*/)
{
	if (fieldDataType(nField) == SQLITE_NULL)
	{
		return szNullValue;
	}
	else
	{
		return (const char*)sqlite3_column_text(m_pVM, nField);
	}
}


const char* CppSQLite3Query::getStringField(const char* szField, const char* szNullValue/*=""*/)
{
	int nField = fieldIndex(szField);
	return getStringField(nField, szNullValue);
}


const unsigned char* CppSQLite3Query::getBlobField(int nField, int& nLen)
{
	checkVM();

	if (nField < 0 || nField > m_nCols-1)
	{
		throw CppSQLite3Exception(CPPSQLITE_ERROR,
								"Invalid field index requested",
								DONT_DELETE_MSG);
	}

	nLen = sqlite3_column_bytes(m_pVM, nField);
	return (const unsigned char*)sqlite3_column_blob(m_pVM, nField);
}


const unsigned char* CppSQLite3Query::getBlobField(const char* szField, int& nLen)
{
	int nField = fieldIndex(szField);
	return getBlobField(nField, nLen);
}


bool CppSQLite3Query::fieldIsNull(int nField)
{
	return (fieldDataType(nField) == SQLITE_NULL);
}


bool CppSQLite3Query::fieldIsNull(const char* szField)
{
	int nField = fieldIndex(szField);
	return (fieldDataType(nField) == SQLITE_NULL);
}


int CppSQLite3Query::fieldIndex(const char* szField)
{
	checkVM();

	if (szField)
	{
		for (int nField = 0; nField < m_nCols; nField++)
		{
			const char* szTemp = sqlite3_column_name(m_pVM, nField);

			if (strcmp(szField, szTemp) == 0)
			{
				return nField;
			}
		}
	}

	throw CppSQLite3Exception(CPPSQLITE_ERROR,
							"Invalid field name requested",
							DONT_DELETE_MSG);
}


const char* CppSQLite3Query::fieldName(int nCol)
{
	checkVM();

	if (nCol < 0 || nCol > m_nCols-1)
	{
		throw CppSQLite3Exception(CPPSQLITE_ERROR,
								"Invalid field index requested",
								DONT_DELETE_MSG);
	}

	return sqlite3_column_name(m_pVM, nCol);
}


const char* CppSQLite3Query::fieldDeclType(int nCol)
{
	checkVM();

	if (nCol < 0 || nCol > m_nCols-1)
	{
		throw CppSQLite3Exception(CPPSQLITE_ERROR,
								"Invalid field index requested",
								DONT_DELETE_MSG);
	}

	return sqlite3_column_decltype(m_pVM, nCol);
}


int CppSQLite3Query::fieldDataType(int nCol)
{
	checkVM();

	if (nCol < 0 || nCol > m_nCols-1)
	{
		throw CppSQLite3Exception(CPPSQLITE_ERROR,
								"Invalid field index requested",
								DONT_DELETE_MSG);
	}

	return sqlite3_column_type(m_pVM, nCol);
}


bool CppSQLite3Query::eof()
{
	checkVM();
	return m_bEof;
}


void CppSQLite3Query::nextRow()
{
	checkVM();

	int nRet = sqlite3_step(m_pVM);

	if (nRet == SQLITE_DONE)
	{
		// no rows
		m_bEof = true;
	}
	else if (nRet == SQLITE_ROW)
	{
		// more rows, nothing to do
	}
	else
	{
		nRet = sqlite3_finalize(m_pVM);
		m_pVM = 0;
		const char* szError = sqlite3_errmsg(m_pDB);
		throw CppSQLite3Exception(nRet,
								(char*)szError,
								DONT_DELETE_MSG);
	}
}


void CppSQLite3Query::finalize()
{
	if (m_pVM && m_bOwnVM)
	{
		int nRet = sqlite3_finalize(m_pVM);
		m_pVM = 0;
		if (nRet != SQLITE_OK)
		{
			const char* szError = sqlite3_errmsg(m_pDB);
			throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
		}
	}
}


void CppSQLite3Query::checkVM()
{
	if (m_pVM == 0)
	{
		throw CppSQLite3Exception(CPPSQLITE_ERROR,
								"Null Virtual Machine pointer",
								DONT_DELETE_MSG);
	}
}


////////////////////////////////////////////////////////////////////////////////

CppSQLite3Table::CppSQLite3Table()
{
	m_paszResults = 0;
	m_nRows = 0;
	m_nCols = 0;
	m_nCurrentRow = 0;
}


CppSQLite3Table::CppSQLite3Table(const CppSQLite3Table& rTable)
{
	m_paszResults = rTable.m_paszResults;
	// Only one object can own the results
	const_cast<CppSQLite3Table&>(rTable).m_paszResults = 0;
	m_nRows = rTable.m_nRows;
	m_nCols = rTable.m_nCols;
	m_nCurrentRow = rTable.m_nCurrentRow;
}


CppSQLite3Table::CppSQLite3Table(char** paszResults, int nRows, int nCols)
{
	m_paszResults = paszResults;
	m_nRows = nRows;
	m_nCols = nCols;
	m_nCurrentRow = 0;
}


CppSQLite3Table::~CppSQLite3Table()
{
	try
	{
		finalize();
	}
	catch (...)
	{
	}
}


CppSQLite3Table& CppSQLite3Table::operator=(const CppSQLite3Table& rTable)
{
	try
	{
		finalize();
	}
	catch (...)
	{
	}
	m_paszResults = rTable.m_paszResults;
	// Only one object can own the results
	const_cast<CppSQLite3Table&>(rTable).m_paszResults = 0;
	m_nRows = rTable.m_nRows;
	m_nCols = rTable.m_nCols;
	m_nCurrentRow = rTable.m_nCurrentRow;
	return *this;
}


void CppSQLite3Table::finalize()
{
	if (m_paszResults)
	{
		sqlite3_free_table(m_paszResults);
		m_paszResults = 0;
	}
}


int CppSQLite3Table::numFields()
{
	checkResults();
	return m_nCols;
}


int CppSQLite3Table::numRows()
{
	checkResults();
	return m_nRows;
}


const char* CppSQLite3Table::fieldValue(int nField)
{
	checkResults();

	if (nField < 0 || nField > m_nCols-1)
	{
		throw CppSQLite3Exception(CPPSQLITE_ERROR,
								"Invalid field index requested",
								DONT_DELETE_MSG);
	}

	int nIndex = (m_nCurrentRow*m_nCols) + m_nCols + nField;
	return m_paszResults[nIndex];
}


const char* CppSQLite3Table::fieldValue(const char* szField)
{
	checkResults();

	if (szField)
	{
		for (int nField = 0; nField < m_nCols; nField++)
		{
			if (strcmp(szField, m_paszResults[nField]) == 0)
			{
				int nIndex = (m_nCurrentRow*m_nCols) + m_nCols + nField;
				return m_paszResults[nIndex];
			}
		}
	}

	throw CppSQLite3Exception(CPPSQLITE_ERROR,
							"Invalid field name requested",
							DONT_DELETE_MSG);
}


int CppSQLite3Table::getIntField(int nField, int nNullValue/*=0*/)
{
	if (fieldIsNull(nField))
	{
		return nNullValue;
	}
	else
	{
		return atoi(fieldValue(nField));
	}
}


int CppSQLite3Table::getIntField(const char* szField, int nNullValue/*=0*/)
{
	if (fieldIsNull(szField))
	{
		return nNullValue;
	}
	else
	{
		return atoi(fieldValue(szField));
	}
}


double CppSQLite3Table::getFloatField(int nField, double fNullValue/*=0.0*/)
{
	if (fieldIsNull(nField))
	{
		return fNullValue;
	}
	else
	{
		return atof(fieldValue(nField));
	}
}


double CppSQLite3Table::getFloatField(const char* szField, double fNullValue/*=0.0*/)
{
	if (fieldIsNull(szField))
	{
		return fNullValue;
	}
	else
	{
		return atof(fieldValue(szField));
	}
}


const char* CppSQLite3Table::getStringField(int nField, const char* szNullValue/*=""*/)
{
	if (fieldIsNull(nField))
	{
		return szNullValue;
	}
	else
	{
		return fieldValue(nField);
	}
}


const char* CppSQLite3Table::getStringField(const char* szField, const char* szNullValue/*=""*/)
{
	if (fieldIsNull(szField))
	{
		return szNullValue;
	}
	else
	{
		return fieldValue(szField);
	}
}


bool CppSQLite3Table::fieldIsNull(int nField)
{
	checkResults();
	return (fieldValue(nField) == 0);
}


bool CppSQLite3Table::fieldIsNull(const char* szField)
{
	checkResults();
	return (fieldValue(szField) == 0);
}


const char* CppSQLite3Table::fieldName(int nCol)
{
	checkResults();

	if (nCol < 0 || nCol > m_nCols-1)
	{
		throw CppSQLite3Exception(CPPSQLITE_ERROR,
								"Invalid field index requested",
								DONT_DELETE_MSG);
	}

	return m_paszResults[nCol];
}


void CppSQLite3Table::setRow(int nRow)
{
	checkResults();

	if (nRow < 0 || nRow > m_nRows-1)
	{
		throw CppSQLite3Exception(CPPSQLITE_ERROR,
								"Invalid row index requested",
								DONT_DELETE_MSG);
	}

	m_nCurrentRow = nRow;
}


void CppSQLite3Table::checkResults()
{
	if (m_paszResults == 0)
	{
		throw CppSQLite3Exception(CPPSQLITE_ERROR,
								"Null Results pointer",
								DONT_DELETE_MSG);
	}
}


////////////////////////////////////////////////////////////////////////////////

CppSQLite3Statement::CppSQLite3Statement()
{
	m_pDB = 0;
	m_pVM = 0;
}


CppSQLite3Statement::CppSQLite3Statement(const CppSQLite3Statement& rStatement)
{
	m_pDB = rStatement.m_pDB;
	m_pVM = rStatement.m_pVM;
	// Only one object can own VM
	const_cast<CppSQLite3Statement&>(rStatement).m_pVM = 0;
}


CppSQLite3Statement::CppSQLite3Statement(sqlite3* pDB, sqlite3_stmt* pVM)
{
	m_pDB = pDB;
	m_pVM = pVM;
}


CppSQLite3Statement::~CppSQLite3Statement()
{
	try
	{
		finalize();
	}
	catch (...)
	{
	}
}


CppSQLite3Statement& CppSQLite3Statement::operator=(const CppSQLite3Statement& rStatement)
{
	m_pDB = rStatement.m_pDB;
	m_pVM = rStatement.m_pVM;
	// Only one object can own VM
	const_cast<CppSQLite3Statement&>(rStatement).m_pVM = 0;
	return *this;
}


int CppSQLite3Statement::execDML()
{
	checkDB();
	checkVM();

	const char* szError=0;

	int nRet = sqlite3_step(m_pVM);

	if (nRet == SQLITE_DONE)
	{
		int nRowsChanged = sqlite3_changes(m_pDB);

		nRet = sqlite3_reset(m_pVM);

		if (nRet != SQLITE_OK)
		{
			szError = sqlite3_errmsg(m_pDB);
			throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
		}

		return nRowsChanged;
	}
	else
	{
		nRet = sqlite3_reset(m_pVM);
		szError = sqlite3_errmsg(m_pDB);
		throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
	}
}


CppSQLite3Query CppSQLite3Statement::execQuery()
{
	checkDB();
	checkVM();

	int nRet = sqlite3_step(m_pVM);

	if (nRet == SQLITE_DONE)
	{
		// no rows
		return CppSQLite3Query(m_pDB, m_pVM, true/*eof*/, false);
	}
	else if (nRet == SQLITE_ROW)
	{
		// at least 1 row
		return CppSQLite3Query(m_pDB, m_pVM, false/*eof*/, false);
	}
	else
	{
		nRet = sqlite3_reset(m_pVM);
		const char* szError = sqlite3_errmsg(m_pDB);
		throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
	}
}


void CppSQLite3Statement::bind(int nParam, const char* szValue)
{
	checkVM();
	int nRes = sqlite3_bind_text(m_pVM, nParam, szValue, -1, SQLITE_TRANSIENT);

	if (nRes != SQLITE_OK)
	{
		throw CppSQLite3Exception(nRes,
								"Error binding string param",
								DONT_DELETE_MSG);
	}
}


void CppSQLite3Statement::bind(int nParam, const int nValue)
{
	checkVM();
	int nRes = sqlite3_bind_int(m_pVM, nParam, nValue);

	if (nRes != SQLITE_OK)
	{
		throw CppSQLite3Exception(nRes,
								"Error binding int param",
								DONT_DELETE_MSG);
	}
}


void CppSQLite3Statement::bind(int nParam, const double dValue)
{
	checkVM();
	int nRes = sqlite3_bind_double(m_pVM, nParam, dValue);

	if (nRes != SQLITE_OK)
	{
		throw CppSQLite3Exception(nRes,
								"Error binding double param",
								DONT_DELETE_MSG);
	}
}


void CppSQLite3Statement::bind(int nParam, const unsigned char* blobValue, int nLen)
{
	checkVM();
	int nRes = sqlite3_bind_blob(m_pVM, nParam,
								(const void*)blobValue, nLen, SQLITE_TRANSIENT);

	if (nRes != SQLITE_OK)
	{
		throw CppSQLite3Exception(nRes,
								"Error binding blob param",
								DONT_DELETE_MSG);
	}
}

	
void CppSQLite3Statement::bindNull(int nParam)
{
	checkVM();
	int nRes = sqlite3_bind_null(m_pVM, nParam);

	if (nRes != SQLITE_OK)
	{
		throw CppSQLite3Exception(nRes,
								"Error binding NULL param",
								DONT_DELETE_MSG);
	}
}


void CppSQLite3Statement::reset()
{
	if (m_pVM)
	{
		int nRet = sqlite3_reset(m_pVM);

		if (nRet != SQLITE_OK)
		{
			const char* szError = sqlite3_errmsg(m_pDB);
			throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
		}
	}
}


void CppSQLite3Statement::finalize()
{
	if (m_pVM)
	{
		int nRet = sqlite3_finalize(m_pVM);
		m_pVM = 0;

		if (nRet != SQLITE_OK)
		{
			const char* szError = sqlite3_errmsg(m_pDB);
			throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
		}
	}
}


void CppSQLite3Statement::checkDB()
{
	if (m_pDB == 0)
	{
		throw CppSQLite3Exception(CPPSQLITE_ERROR,
								"Database not open",
								DONT_DELETE_MSG);
	}
}


void CppSQLite3Statement::checkVM()
{
	if (m_pVM == 0)
	{
		throw CppSQLite3Exception(CPPSQLITE_ERROR,
								"Null Virtual Machine pointer",
								DONT_DELETE_MSG);
	}
}


////////////////////////////////////////////////////////////////////////////////

CppSQLite3DB::CppSQLite3DB()
{
	m_pDB = 0;
	m_nBusyTimeoutMs = 60000; // 60 seconds
}


CppSQLite3DB::CppSQLite3DB(const CppSQLite3DB& db)
{
	m_pDB = db.m_pDB;
	m_nBusyTimeoutMs = 60000; // 60 seconds
}


CppSQLite3DB::~CppSQLite3DB()
{
	close();
}


CppSQLite3DB& CppSQLite3DB::operator=(const CppSQLite3DB& db)
{
	m_pDB = db.m_pDB;
	m_nBusyTimeoutMs = 60000; // 60 seconds
	return *this;
}



void CppSQLite3DB::open(const char* szFile)
{
	char szFileEncrypt[MAX_PATH];
	char FileName[MAX_PATH];

//
//#define SQLITE_ENCRYPT
//

#ifdef SQLITE_ENCRYPT
#define SQLITE_ENCRYPT_KEY "34B6D05E-0874-4c83-A0DB-7A8D1E23F488"

	//
	//
	//
	FILE * fp = NULL;
	int encrypt = 0;
	sprintf_s( szFileEncrypt, sizeof( szFileEncrypt ), "%s.data", szFile );

	if ( ( fp = fopen( szFileEncrypt, "rb" ) ) != NULL )
	{
		encrypt = 1;
		fclose( fp );				
	}
	else
	{
		sprintf_s( szFileEncrypt, sizeof( szFileEncrypt ), "%s.db", szFile );
		if ( ( fp = fopen( szFileEncrypt, "rb" ) ) != NULL )
		{
			fclose( fp );
		}
		else
		{
	//		AD_ERROR( "Cannot OPEN data file %s\n", szFile );
			return;
		}
	}
#else
	sprintf_s( szFileEncrypt, sizeof( szFileEncrypt ), "%s.db", szFile );
#endif

	GB2312_2_UTF8(FileName, MAX_PATH, szFileEncrypt, 0);
	
	const char * UTF8_FileName = &FileName[0] ;

	int nRet = sqlite3_open(UTF8_FileName, &m_pDB);

	if (nRet != SQLITE_OK)
	{
		const char* szError = sqlite3_errmsg(m_pDB);
		throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
	}

#ifdef SQLITE_ENCRYPT
	if ( encrypt )
		sqlite3_key( m_pDB, SQLITE_ENCRYPT_KEY, strlen( SQLITE_ENCRYPT_KEY ) );
#endif

	setBusyTimeout(m_nBusyTimeoutMs);
}


void CppSQLite3DB::close()
{
	if (m_pDB)
	{
		sqlite3_close(m_pDB);
		m_pDB = 0;
	}
}


CppSQLite3Statement CppSQLite3DB::compileStatement(const char* szSQL)
{
	checkDB();

	sqlite3_stmt* pVM = compile(szSQL);
	return CppSQLite3Statement(m_pDB, pVM);
}


bool CppSQLite3DB::tableExists(const char* szTable)
{
	char szSQL[128];
	sprintf(szSQL,
			"select count(*) from sqlite_master where type='table' and name='%s'",
			szTable);
	int nRet = execScalar(szSQL);
	return (nRet > 0);
}


int CppSQLite3DB::execDML(const char* szSQL)
{
	checkDB();

	char* szError=0;

	int nRet = sqlite3_exec(m_pDB, szSQL, 0, 0, &szError);

	if (nRet == SQLITE_OK)
	{
		return sqlite3_changes(m_pDB);
	}
	else
	{
		throw CppSQLite3Exception(nRet, szError);
	}
}


CppSQLite3Query CppSQLite3DB::execQuery(const char* szSQL)
{
	checkDB();

	sqlite3_stmt* pVM = compile(szSQL);

	int nRet = sqlite3_step(pVM);

	if (nRet == SQLITE_DONE)
	{
		// no rows
		return CppSQLite3Query(m_pDB, pVM, true/*eof*/);
	}
	else if (nRet == SQLITE_ROW)
	{
		// at least 1 row
		return CppSQLite3Query(m_pDB, pVM, false/*eof*/);
	}
	else
	{
		nRet = sqlite3_finalize(pVM);
		const char* szError= sqlite3_errmsg(m_pDB);
		throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
	}
}


int CppSQLite3DB::execScalar(const char* szSQL)
{
	CppSQLite3Query q = execQuery(szSQL);

	if (q.eof() || q.numFields() < 1)
	{
		throw CppSQLite3Exception(CPPSQLITE_ERROR,
								"Invalid scalar query",
								DONT_DELETE_MSG);
	}

	return atoi(q.fieldValue(0));
}


CppSQLite3Table CppSQLite3DB::getTable(const char* szSQL)
{
	checkDB();

	char* szError=0;
	char** paszResults=0;
	int nRet;
	int nRows(0);
	int nCols(0);

	nRet = sqlite3_get_table(m_pDB, szSQL, &paszResults, &nRows, &nCols, &szError);

	if (nRet == SQLITE_OK)
	{
		return CppSQLite3Table(paszResults, nRows, nCols);
	}
	else
	{
		throw CppSQLite3Exception(nRet, szError);
	}
}


sqlite_int64 CppSQLite3DB::lastRowId()
{
	return sqlite3_last_insert_rowid(m_pDB);
}


void CppSQLite3DB::setBusyTimeout(int nMillisecs)
{
	m_nBusyTimeoutMs = nMillisecs;
	sqlite3_busy_timeout(m_pDB, m_nBusyTimeoutMs);
}


void CppSQLite3DB::checkDB()
{
	if (!m_pDB)
	{
		throw CppSQLite3Exception(CPPSQLITE_ERROR,
								"Database not open",
								DONT_DELETE_MSG);
	}
}


sqlite3_stmt* CppSQLite3DB::compile(const char* szSQL)
{
	checkDB();

	char* szError=0;
	const char* szTail=0;
	sqlite3_stmt* pVM;

	int nRet = sqlite3_prepare(m_pDB, szSQL, -1, &pVM, &szTail);

	if (nRet != SQLITE_OK)
	{
		throw CppSQLite3Exception(nRet, szError);
	}

	return pVM;
}


int sqlite3_encode_binary(const unsigned char *in, int n, unsigned char *out){
  int i, j, e, m;
  int cnt[256];
  if( n<=0 ){
    out[0] = 'x';
    out[1] = 0;
    return 1;
  }
  memset(cnt, 0, sizeof(cnt));
  for(i=n-1; i>=0; i--){ cnt[in[i]]++; }
  m = n;
  for(i=1; i<256; i++){
    int sum;
    if( i=='\'' ) continue;
    sum = cnt[i] + cnt[(i+1)&0xff] + cnt[(i+'\'')&0xff];
    if( sum<m ){
      m = sum;
      e = i;
      if( m==0 ) break;
    }
  }
  out[0] = e;
  j = 1;
  for(i=0; i<n; i++){
    int c = (in[i] - e)&0xff;
    if( c==0 ){
      out[j++] = 1;
      out[j++] = 1;
    }else if( c==1 ){
      out[j++] = 1;
      out[j++] = 2;
    }else if( c=='\'' ){
      out[j++] = 1;
      out[j++] = 3;
    }else{
      out[j++] = c;
    }
  }
  out[j] = 0;
  return j;
}


int sqlite3_decode_binary(const unsigned char *in, unsigned char *out){
  int i, c, e;
  e = *(in++);
  i = 0;
  while( (c = *(in++))!=0 ){
    if( c==1 ){
      c = *(in++);
      if( c==1 ){
        c = 0;
      }else if( c==2 ){
        c = 1;
      }else if( c==3 ){
        c = '\'';
      }else{
        return -1;
      }
    }
    out[i++] = (c + e)&0xff;
  }
  return i;
}
